﻿package com.colorpicker{
	/**
	This class creates a gradient saturation of selected hue.
	Crosshair cursor can be dragged over it to select different saturation
	of a color
	
	@author Sharwan Kami <sharwan@gmail.com>
	@version 1.0
	@history 2009-05-10
	
	* 
	* This file is part of E-Card plugin, from zetaprints.com
	* 
	
	@usage
	Activate with:
		<code>
			//create the instance of the ColorPickerCanvas
			colorCanvas=new ColorPickerCanvas();
			colorCanvas.x=8;
			colorCanvas.y=30;
			addChild(colorCanvas);
			//initialize to draw the gradient saturation of the color
			colorCanvas.init();
		</code>
	
	*/
	import flash.display.MovieClip;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.GradientType;
	import flash.display.Sprite;
	import flash.geom.Matrix;	
	import flash.geom.Rectangle;
	import flash.events.Event;
	import flash.events.MouseEvent;

	public class ColorPickerCanvas extends MovieClip{
		private var w=200;//canvas width
		private var h=200;//canvas height
		private var bd:BitmapData;
		private var bm:Bitmap;
		
		//color gradient values
		private const fillTypeB:String =GradientType.LINEAR;
		private var colorsB:Array = [0xff0000,0xFF0000];
		private var alphasB:Array = [1,1];
		private var ratiosB:Array = [10,245];
		private var matrixB:Matrix=new Matrix();
		
		//black gradient values
		private const fillTypeM:String =GradientType.LINEAR;
	    private var colorsM:Array = [0xFFFFFF, 0x000000];
	    private var alphasM:Array = [0,1];
    	private var ratiosM:Array = [0, 255];
	    private var matrixM:Matrix = new Matrix();
		
		//embet the source movieclip for cursor from assets.swf
		[Embed(source='../../assets.swf', symbol="ColorCursor")]
		private var ColorCursor:Class;
		public var colorCursor:Sprite;
		
		private var activeColor:uint=0xff0000;//default active color

		/**
			Constructor
		*/
		function ColorPickerCanvas(){
			//set matrix values for gradients
			matrixB.createGradientBox(200,200,0);
			matrixM.createGradientBox(200,200, 90*Math.PI/180, 0, 0);
		}
		
		/**
		creates bitmap data object with active color
		creates and adds the crosshair pointer
		adds event listeners for crosshair to select color based on its position
		and, draws the gradient based on selected default active color
		*/
		public function init():void{
			bd = new BitmapData(w,h, false, activeColor);
			bm = new Bitmap(bd);
   			addChild(bm);
			
			//add the cursor
			colorCursor=new ColorCursor();
			addChild(colorCursor);
			
			addEventListener(MouseEvent.MOUSE_DOWN,onCursorDown);
			addEventListener(MouseEvent.MOUSE_UP,onCursorUp);
			
			this.draw(activeColor);
		}
		
		private function onCursorDown(e:MouseEvent):void{
			var rect:Rectangle=new Rectangle(0,0,w-1,h);
			colorCursor.x=mouseX;
			colorCursor.y=mouseY;
			colorCursor.startDrag(true,rect);
			
			//add mouseup on stage if the mouse is up outside the canvas
			this.parent.parent.addEventListener(MouseEvent.MOUSE_UP,onStageMouseUp);
		}
		
		private function onCursorUp(e:MouseEvent):void{
			colorCursor.stopDrag();
			setColor();
			dispatchEvent(new Event("saturationChanged"));
		}
		
		//to fix mouseup outside the canvas
		public function onStageMouseUp(e:MouseEvent):void{
			if(e.target!=this){
				colorCursor.stopDrag();
				setColor();
				dispatchEvent(new Event("saturationChanged"));
			}			
			this.parent.parent.removeEventListener(MouseEvent.MOUSE_UP,onStageMouseUp);
		}
		
		/**
		updates the active color based on position of the crosshair
		*/
		private function setColor():void{
			activeColor=bd.getPixel(colorCursor.x,colorCursor.y);
		}
		
		/**
		updates the crosshair position based on passed color
		updates the active color
		dispatches the event to notify color change
		*/
		public function setCursorPosition(c:uint):void{
			var tmpColor=c;
			var steps:uint = 0;
			var rect:Rectangle;
			var r:uint;
			var g:uint;
			var b:uint;
			do{
				rect = bd.getColorBoundsRect(0xFFFFFFFF, 0xFF000000+c, true);
				steps++;
				
				r = c >> 16 & 0xff
				g = c >> 8 & 0xff
				b = c & 0xff;
				r = Math.min(r+1, 255);
				g = Math.min(g+1, 255);
				b = Math.min(b+1, 255);
				
				c = r << 16 | g << 8 | b
			}while(rect.width == 0 && c > 0 && steps < 7000);

			colorCursor.y=0;
			colorCursor.x=0;
			
			colorCursor.y=rect.bottom;
			colorCursor.x=rect.right;
			activeColor=tmpColor;
			dispatchEvent(new Event("colorChanged"));
		}
		
		/**
		creates gradient saturation based on color passed
		*/
		public function draw(color):void{
			//set new color array based on selected color
			colorsB=[0xFFFFFF,"0x"+ZColor.getRGB(color)];
			
			try{
				bd.dispose()
			}catch(e){}
			
			var mc=new MovieClip();
			mc.graphics.clear();
			
			mc.graphics.beginGradientFill(fillTypeB,colorsB,alphasB,ratiosB,matrixB);
			mc.graphics.drawRect(0,0,200,200);
			mc.graphics.endFill();		
			
			mc.graphics.beginGradientFill(fillTypeM, colorsM, alphasM, ratiosM, matrixM);
			mc.graphics.drawRect(0,0,200,200);
			mc.graphics.endFill();			
			
			bd = new BitmapData(mc.width, mc.height);
			bd.draw(mc);	
			bm = new Bitmap(bd);
			addChild(bm);
			
			swapChildren(bm,colorCursor);			
		}
		
		/**
		setter function, sets the active color
		*/
		public function set color(color):void{
			activeColor=color;
		}
		
		/**
		getter function, updates the active color and returns the active color
		*/
		public function get color():uint{
			setColor();
			return activeColor;
		}		
	}
}